/* --- 什么是泛型 ---

在讲解什么是泛型之前，我们先观察Java标准库提供的ArrayList，它可以看作“可变长度”的数组，因为用起来比数组更方便。

实际上ArrayList内部就是一个Object[]数组，配合存储一个当前分配的长度，就可以充当“可变数组”： */
public class ArrayList {
	private Object[] array;
	private int size;

	public void add(Object e) {
		//...
	}

	public void remove(int index) {
		//...
	}

	public Object get(int index) {
		//...
	}
}

/*
如果用上述ArrayList存储String类型，会有这么几个缺点：
	1.需要强制转型；
	2.不方便，易出错。

例如,代码必须这么写：		*/
ArrayList list = new ArrayList();
list.add("Hello");
//获取到Object,必须强制转型为String：
String first = (String) list.get(0);


// 很容易出现ClassCastException，因为容易“误转型”：
list.add(new Integer(123));
//ERROR: ClassCastException:
String second = (String) list.get(1);


//要解决上述问题,我们可以为String单独写一种ArrayList:
public class StringArrayList {
	private String[] array;
	private int size;

	public void add(String e) {}
	public void remove(int index) {}
	public String get(int index) {}
}

//这样一来，存入的必须是String，取出的也一定是String，不需要强制转型，因为编译器会强制检查放入的类型：
StringArrayList list = new StringArrayList();
list.add("Hello");
String first = list.get(0);
list.add(new Integer(123))
//编译错误：不允许放入非String类型


//问题暂时解决
//然而，新的问题是，如果要存储Integer，还需要为Integer单独编写一种ArrayList：
public class IntegerArrayList {
    private Integer[] array;
    private int size;

    public void add(Integer e) {...}
    public void remove(int index) {...}
    public Integer get(int index) {...}
}


/*
实际上，还需要为其他所有class单独编写一种ArrayList：
	LongArrayList
	DoubleArrayList
	PersonArrayList
	...

这是不可能的，JDK的class就有上千个，而且它还不知道其他人编写的class。

为了解决新的问题，我们必须把ArrayList变成一种模板：ArrayList<T>，代码如下： */
public class ArrayList<T> {
	private T[] array;
	private int size;

	public void add(T e) {}
	public void remove(int index) {}
	public T get(int index) {}
}

/*
T可以是任何class。这样一来，我们就实现了：编写一次模版，可以创建任意类型的ArrayList：  */

//创建可以存储String的ArrayList:
ArrayList<String> strList = new ArrayList<String>();

//创建可以存储Float的ArrayList：
ArrayList<Float> floatList = new ArrayLIst<Float>();

//创建可以存储Person的ArrayList：
ArrayList<Person> personList = new ArrayList<Person>();


//-----------------------------------

//因此，泛型就是定义一种模板，例如ArrayList<T>，然后在代码中为用到的类创建对应的ArrayList<类型>：
ArrayList<String> strList = new ArrayList<String>();

//由编译器针对类型作检查：
strList.add("hello"); //OK
String s = strList.get(0); //OK
strList.add(new Integer(123)); //compile error
Integer n = strList.get(0); //compile error

//这样一来，既实现了编写一次，万能匹配，又通过编译器保证了类型安全：这就是泛型。


/* ----------------------------------

--- 向上转型 ---

在Java标准库中的ArrayList<T>实现了List<T>接口,它可以向上转型为List<T>：   */
public class ArrayList<T> implements List<T> {
	//...
}

List<String> list = new ArrayList<String>();


/*
即类型ArrayList<T>可以向上转型为List<T>。

要特别注意：不能把ArrayList<Integer>向上转型为ArrayList<Number>或List<Number>。

这是为什么呢？假设ArrayList<Integer>可以向上转型为ArrayList<Number>，观察一下代码： 		*/

//创建ArrayList<Integer>类型
ArrayList<Integer> integerList = new ArrayList<Integer>();

//添加一个Integer
integerList.add(new Integer(123));

//"向上转型"为ArrayList<Number>:
ArrayList<Number> numberList = integerList;

//添加一个Float,因为Float也是Number
numberList.add(new Float(12.34));

//从ArrayList<Integer>获取索引为1的元素(即添加的Float):
Integer n = integerList.get(1); //ClassCastException


/*
我们把一个ArrayList<Integer>转型为ArrayList<Number>类型后，这个ArrayList<Number>就可以接受Float类型，因为Float是Number的子类。

但是,ArrayList<Number>实际上和ArrayList<Integer>是同一个对象,也就是ArrayList<Integer>类型,它不可能接受Float类型, 所以在获取Integer的时候将产生ClassCastException。

实际上,编译器为了避免这种错误,根本就不允许把ArrayList<Integer>转型为ArrayList<Number>。

<!-- ArrayList<Integer> 和 ArrayList<Number>两者完全没有继承关系。 -->

*/

//-------------------------------------


/* --- 什么是泛型 の 小结 ---

1. 泛型就是编写模板代码来适应任意类型；

2. 泛型的好处是使用时不必对类型进行强制转换，它通过编译器对类型进行检查；

3. 注意泛型的继承关系：可以把ArrayList<Integer>向上转型为List<Integer> (T不能变！);
但不能把ArrayList<Integer>向上转型为ArrayList<Number>（T不能变成父类）。


*/
public class ArrayList<T> {
	private T[] array;
	private int size;

	public void add(T e) {}
	public void remove(int index) {}
	public T get(int index) {}
}